/*
 * maz_mod_ili9225g.c
 *
 *  Created on: 2020年2月18日
 *      Author: Paul
 */

#include <maz_mod_ili9225g.h>
#include <maz_mod_fonts.h>

/*
 * Internal interface
 */
int MAZ_Mod_ili9225g_register_write(uint8_t reg, uint16_t val);
void MAZ_Mod_ili9225g_index_write(uint8_t Index);
void MAZ_Mod_ili9225g_data_write(uint16_t Data);

void MAZ_Mod_ili9225g_gpio_config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init((GPIO_TypeDef *) GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init((GPIO_TypeDef *) GPIOA, &GPIO_InitStruct);

    BL_ON;
}

int MAZ_Mod_ili9225g_select(void)
{
    CS_L;
    return 0;
}

int MAZ_Mod_ili9225g_unselect(void)
{
    CS_H;
    return 0;
}

void MAZ_Mod_ili9225g_init(void)
{
    delay_ms(50);
    RES_L;
    delay_ms(100);
    RES_H;
    delay_ms(50);

    //LCD Init For 2.2inch LCD Panel with ILI9225.
    MAZ_Mod_ili9225g_register_write(0x10, 0x0000); // Set SAP,DSTB,STB
    MAZ_Mod_ili9225g_register_write(0x11, 0x0000); // Set APON,PON,AON,VCI1EN,VC
    MAZ_Mod_ili9225g_register_write(0x12, 0x0000); // Set BT,DC1,DC2,DC3
    MAZ_Mod_ili9225g_register_write(0x13, 0x0000); // Set GVDD
    MAZ_Mod_ili9225g_register_write(0x14, 0x0000); // Set VCOMH/VCOML voltage
    delay_ms(40); // Delay 20 ms

    // Please follow this power on sequence
    MAZ_Mod_ili9225g_register_write(0x11, 0x0018); // Set APON,PON,AON,VCI1EN,VC
    MAZ_Mod_ili9225g_register_write(0x12, 0x1121); // Set BT,DC1,DC2,DC3
    MAZ_Mod_ili9225g_register_write(0x13, 0x0063); // Set GVDD
    MAZ_Mod_ili9225g_register_write(0x14, 0x3961); // Set VCOMH/VCOML voltage
    MAZ_Mod_ili9225g_register_write(0x10, 0x0800); // Set SAP,DSTB,STB
    delay_ms(10); // Delay 10 ms
    MAZ_Mod_ili9225g_register_write(0x11, 0x1038); // Set APON,PON,AON,VCI1EN,VC
    delay_ms(30); // Delay 30 ms

    MAZ_Mod_ili9225g_register_write(0x02, 0x0100); // set 1 line inversion

#if USE_HORIZONTAL//如果定义了横屏
    //R01H:SM=0,GS=0,SS=0 (for details,See the datasheet of ILI9225)
    MAZ_Mod_ili9225g_register_write(0x01, 0x001C); // set the display line number and display direction
    //R03H:BGR=1,ID0=1,ID1=1,AM=1 (for details,See the datasheet of ILI9225)
    MAZ_Mod_ili9225g_register_write(0x03, 0x1038); // set GRAM write direction .
#else//竖屏
    //R01H:SM=0,GS=0,SS=1 (for details,See the datasheet of ILI9225)
    MAZ_Mod_ili9225g_register_write(0x01, 0x011C); // set the display line number and display direction
    //R03H:BGR=1,ID0=1,ID1=1,AM=0 (for details,See the datasheet of ILI9225)
    MAZ_Mod_ili9225g_register_write(0x03, 0x1030); // set GRAM write direction.
#endif

    MAZ_Mod_ili9225g_register_write(0x07, 0x0000); // Display off
    MAZ_Mod_ili9225g_register_write(0x08, 0x0808); // set the back porch and front porch
    MAZ_Mod_ili9225g_register_write(0x0B, 0x1100); // set the clocks number per line
    MAZ_Mod_ili9225g_register_write(0x0C, 0x0000); // CPU interface
    MAZ_Mod_ili9225g_register_write(0x0F, 0x0501); // Set Osc
    MAZ_Mod_ili9225g_register_write(0x15, 0x0020); // Set VCI recycling
    MAZ_Mod_ili9225g_register_write(0x20, 0x0000); // RAM Address
    MAZ_Mod_ili9225g_register_write(0x21, 0x0000); // RAM Address

    //------------------------ Set GRAM area --------------------------------//
    MAZ_Mod_ili9225g_register_write(0x30, 0x0000);
    MAZ_Mod_ili9225g_register_write(0x31, 0x00DB);
    MAZ_Mod_ili9225g_register_write(0x32, 0x0000);
    MAZ_Mod_ili9225g_register_write(0x33, 0x0000);
    MAZ_Mod_ili9225g_register_write(0x34, 0x00DB);
    MAZ_Mod_ili9225g_register_write(0x35, 0x0000);
    MAZ_Mod_ili9225g_register_write(0x36, 0x00AF);
    MAZ_Mod_ili9225g_register_write(0x37, 0x0000);
    MAZ_Mod_ili9225g_register_write(0x38, 0x00DB);
    MAZ_Mod_ili9225g_register_write(0x39, 0x0000);

    //------------------------ Adjust the Gamma 2.2 Curve -------------------//
    MAZ_Mod_ili9225g_register_write(0x50, 0x0603);
    MAZ_Mod_ili9225g_register_write(0x51, 0x080D);
    MAZ_Mod_ili9225g_register_write(0x52, 0x0D0C);
    MAZ_Mod_ili9225g_register_write(0x53, 0x0205);
    MAZ_Mod_ili9225g_register_write(0x54, 0x040A);
    MAZ_Mod_ili9225g_register_write(0x55, 0x0703);
    MAZ_Mod_ili9225g_register_write(0x56, 0x0300);
    MAZ_Mod_ili9225g_register_write(0x57, 0x0400);
    MAZ_Mod_ili9225g_register_write(0x58, 0x0B00);
    MAZ_Mod_ili9225g_register_write(0x59, 0x0017);

    MAZ_Mod_ili9225g_register_write(0x0F, 0x0701); // Vertical RAM Address Position
    MAZ_Mod_ili9225g_register_write(0x07, 0x0012); // Vertical RAM Address Position
    delay_ms(50); // Delay 50 ms
    MAZ_Mod_ili9225g_register_write(0x07, 0x1017); // Vertical RAM Address Position
}

int MAZ_Mod_ili9225g_set_position(uint16_t x, uint16_t y)
{
#if USE_HORIZONTAL//如果定义了横屏
    MAZ_Mod_ili9225g_register_write(0x21, x);
    MAZ_Mod_ili9225g_register_write(0x20, y);
#else//竖屏
    MAZ_Mod_ili9225g_register_write(0x20, x);
    MAZ_Mod_ili9225g_register_write(0x21, y);
#endif
    MAZ_Mod_ili9225g_index_write(0x22);

    return MAZRET_NOERR;
}

int MAZ_Mod_ili9225g_set_region(MAZMOD_ILI9225G index, uint32_t x_start, uint32_t y_start, uint32_t x_end, uint32_t y_end)
{
#if USE_HORIZONTAL//如果定义了横屏
    MAZ_Mod_ili9225g_register_write(0x38, x_end);
    MAZ_Mod_ili9225g_register_write(0x39, x_start);
    MAZ_Mod_ili9225g_register_write(0x36, y_end);
    MAZ_Mod_ili9225g_register_write(0x37, y_start);
    MAZ_Mod_ili9225g_register_write(0x21, x_start);
    MAZ_Mod_ili9225g_register_write(0x20, y_start);
#else//竖屏
    MAZ_Mod_ili9225g_register_write(0x36, x_end);
    MAZ_Mod_ili9225g_register_write(0x37, x_start);
    MAZ_Mod_ili9225g_register_write(0x38, y_end);
    MAZ_Mod_ili9225g_register_write(0x39, y_start);
    MAZ_Mod_ili9225g_register_write(0x20, x_start);
    MAZ_Mod_ili9225g_register_write(0x21, y_start);
#endif
    MAZ_Mod_ili9225g_index_write(0x22);

    return MAZRET_NOERR;
}

int MAZ_Mod_ili9225g_draw_pixel(MAZMOD_ILI9225G index, uint16_t x, uint16_t y, uint16_t color)
{
    MAZ_Mod_ili9225g_set_position(x, y);
    MAZ_Mod_ili9225g_data_write(color);

    return MAZRET_NOERR;
}

int MAZ_Mod_ili9225g_draw_char(MAZMOD_ILI9225G index, uint16_t x, uint16_t y, char ch, FontDef font, uint16_t color, uint16_t bgcolor)
{
    uint32_t i, b, j;

    MAZ_Mod_ili9225g_set_region(index, x, y, x + font.width - 1, y + font.height - 1);

    for (i = 0; i < font.height; i++)
    {
        b = font.data[(ch - 32) * font.height + i];
        for (j = 0; j < font.width; j++)
        {
            if ((b << j) & 0x8000)
            {
                MAZ_Mod_ili9225g_data_write(color);
            }
            else
            {
                MAZ_Mod_ili9225g_data_write(bgcolor);
            }
        }
    }

    return MAZRET_NOERR;
}

int MAZ_Mod_ili9225g_draw_string(MAZMOD_ILI9225G index, uint16_t x, uint16_t y, const char *str, FontDef font, uint16_t color, uint16_t bgcolor)
{
    while (*str)
    {
        if (x + font.width >= 176)
        {
            x = 0;
            y += font.height;
            if (y + font.height >= 220)
            {
                break;
            }

            if (*str == ' ')
            {
                // skip spaces in the beginning of the new line
                str++;
                continue;
            }
        }

        MAZ_Mod_ili9225g_draw_char(index, x, y, *str, font, color, bgcolor);
        x += font.width;
        str++;
    }

    return MAZRET_NOERR;
}

int MAZ_Mod_ili9225g_clear_screen(uint16_t Color)
{
    unsigned int i, m;
    MAZ_Mod_ili9225g_set_region(MAZMOD_ILI9225G0, 0, 0, Y_MAX_PIXEL - 1, X_MAX_PIXEL - 1);

    RD_H;
    DC_H;

    for (i = 0; i < X_MAX_PIXEL; i++)
    {
        for (m = 0; m < Y_MAX_PIXEL; m++)
        {
            WR_L;
            GPIO_WriteLow(GPIOB, (Color >> 8));
            WR_H;
            WR_L;
            GPIO_WriteLow(GPIOB, (Color & 0xff));
            WR_H;
        }
    }

    DC_L;

    return MAZRET_NOERR;
}

int MAZ_Mod_ili9225g_show_image(const uint8_t *p)
{
    int i;
    uint8_t picH, picL;
    MAZ_Mod_ili9225g_set_region(MAZMOD_ILI9225G0, 0, 0, 175, 219);     //坐标设置

    RD_H;
    DC_H;

    for (i = 0; i < 176 * 220; i++)
    {
        picL = *(p++);  //数据低位在前
        picH = *(p++);
        WR_L;
        GPIO_WriteLow(GPIOB, picH);
        WR_H;

        WR_L;
        GPIO_WriteLow(GPIOB, picL);
        WR_H;
    }

    return MAZRET_NOERR;
}

/*
 * Internal interface
 */
int MAZ_Mod_ili9225g_register_write(uint8_t reg, uint16_t val)
{
    RD_H;
    DC_L;
    WR_L;

    GPIO_WriteLow(GPIOB, reg);
    WR_H;

    DC_H;
    WR_L;
    GPIO_WriteLow(GPIOB, val >> 8);
    WR_H;

    WR_L;

    GPIO_WriteLow(GPIOB, val & 0xff);

    WR_H;

    return 0;
}

void MAZ_Mod_ili9225g_index_write(uint8_t Index)
{
    DC_L;
    RD_H;
    WR_L;
    GPIO_WriteLow(GPIOB, Index);
    WR_H;
}

void MAZ_Mod_ili9225g_data_write(uint16_t Data)
{
    RD_H;
    DC_H;

    WR_L;
    GPIO_WriteLow(GPIOB, Data >> 8);
    WR_H;

    WR_L;
    GPIO_WriteLow(GPIOB, Data);
    WR_H;
}

